import time
import app.util.rpc as rpc
from typing import List


def get_latest_txs(block_count: int) -> List[dict]:
    result = list()
    block_hash = rpc.get_latest_block_hash()
    for _ in range(block_count):
        block = rpc.get_block(block_hash, 2)
        block_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(block['time']))
        for tx in block['tx']:
            result.append({
                "txid": tx['txid'],
                "isRisky": is_risky_tx(tx),
                "balance": util.get_total_balance(tx),
                "time": block_time
            })
    result = sorted(result, reverse=True, key=lambda item: item['balance'])
    risky_txs = filter(lambda item: item['isRisky'], result)
    non_risky_txs = filter(lambda item: not item['isRisky'], result)
    return list(risky_txs) + list(non_risky_txs)


def is_risky_tx(tx: dict) -> bool:
    # outputs = util.get_tx_outputs(tx)
    # inputs = data.get_transaction_inputs(tx)
    # addr_tuple = (out[0] for out in outputs)
    # return has_malicious_account(addr_tuple)
    return False

# def is_malicious_account(addr: str) -> bool:
#     return addr in malicious_accounts
#
#
# def has_malicious_account(addr_iter) -> bool:
#     for addr in addr_iter:
#         if addr in malicious_accounts:
#             return True
#     return False
#
#
# def add_malicious_account(addr: str, message: str, abuser: str):
#     created_at = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(datetime.now().timestamp())))
#     mysql.insert_malicious_account(addr, message, abuser, created_at)
#     acc = mysql.MaliciousAccount(addr, message, abuser, created_at)
#     if addr not in malicious_accounts:
#         malicious_accounts[addr] = acc
#     else:
#         malicious_accounts[addr].append(acc)
#     pass
#
#
# def get_malicious_account_abuses(addr: str) -> List[dict]:
#     items = malicious_accounts.get(addr)
#     if items is not None:
#         return [{
#             "message": item.message,
#             "translatedMessage": translate(item.message),
#             "info": f'{item.abuser} uploaded at {item.created_at}'
#         } for item in items]
#     return list()
#
#
# def get_relevant_malicious_accounts(addr: str) -> List[dict]:
#     explorer_addr = blockexplorer.get_address(addr)
#     txids = [tx.hash for tx in explorer_addr.transactions]
#     result = list()
#     for txid in txids:
#         tx = cli.get_transaction(txid)
#         # inputs = cli.get_tx_inputs(tx)
#         outputs = util.get_tx_outputs(tx)
#         addr_iter = [item[0] for item in outputs]
#         for item in addr_iter:
#             if item != addr:
#                 abuses = get_malicious_account_abuses(item)
#                 if len(abuses) > 0:
#                     result.append({
#                         "address": item,
#                         "abuses": abuses
#                     })
#     return result
#
#
# def is_risky_tx(tx: dict) -> bool:
#     outputs = util.get_tx_outputs(tx)
#     # inputs = data.get_transaction_inputs(tx)
#     addr_tuple = (out[0] for out in outputs)
#     return has_malicious_account(addr_tuple)
#
#
# def get_input_tx_tree(root_txid: str, depth: int, risky_only: bool) -> dict:
#     assert depth >= 1
#     root_tx = {
#         "name": root_txid,
#         "isRisky": is_risky_tx(cli.get_transaction(root_txid)),
#     }
#     tx_queue = Queue()
#     tx_queue.put(root_tx)
#     for _ in range(depth - 1):
#         qsize = tx_queue.qsize()
#         for _ in range(qsize):
#             node = tx_queue.get()
#             children = list()
#             input_txs = get_input_txs(node['name'])
#             for tx in input_txs:
#                 tx['name'] = tx.pop('txid')
#                 children.append(tx)
#                 if risky_only and not tx['isRisky']:
#                     continue
#                 tx_queue.put(tx)
#             if len(children) > 0:
#                 node['children'] = children
#     return root_tx
#
#
# def get_tx_outputs(txid: str) -> List[dict]:
#     tx = cli.get_transaction(txid)
#     outputs = util.get_tx_outputs(tx)
#     return [{
#         "address": item[0],
#         "balance": item[1],
#         "isMalicious": is_malicious_account(item[0])
#     } for item in outputs]
#
#
# def get_tx_inputs(txid: str) -> List[dict]:
#     tx = cli.get_transaction(txid)
#     inputs = util.get_tx_inputs(tx)
#     return [{
#         "address": item[0],
#         "balance": item[1],
#         "isMalicious": is_malicious_account(item[0])
#     } for item in inputs]
#
#
# def get_input_txs(txid: str) -> List[dict]:
#     tx = cli.get_transaction(txid)
#     result = list()
#     if 'coinbase' not in tx['vin'][0]:
#         for item in tx['vin']:
#             spent_txid: str = item['txid']
#             spent_tx = cli.get_transaction(spent_txid)
#             result.append({
#                 "txid": spent_txid,
#                 "isRisky": is_risky_tx(spent_tx),
#             })
#     return result
#
#
# def get_all_txs_of_account(addr: str) -> List[dict]:
#     explorer_addr = blockexplorer.get_address(addr)
#     result = list()
#     for tx in explorer_addr.transactions:
#         is_risky = False
#         for item in tx.inputs + tx.outputs:
#             if is_malicious_account(item.address):
#                 is_risky = True
#                 break
#         result.append({
#             "txid": tx.hash,
#             "isRisky": is_risky
#         })
#     return result
#
#
# def get_payer_txs_of_account(addr: str) -> List[dict]:
#     explorer_addr = blockexplorer.get_address(addr)
#     result = list()
#     for tx in explorer_addr.transactions:
#         inputs = ((item.address, item.value) for item in tx.inputs)
#         inputs = list(filter(lambda item: item[0] == addr, inputs))
#         if len(inputs) > 0:
#             balance = 0
#             for item in inputs:
#                 balance += item[1]
#             balance /= 1e8
#             addr_iter = (item.address for item in tx.inputs + tx.outputs)
#             is_risky = has_malicious_account(addr_iter)
#             result.append({
#                 "txid": tx.hash,
#                 "balance": balance,
#                 "isRisky": is_risky
#             })
#     return result
#
#
# def get_payee_txs_of_account(addr: str) -> List[dict]:
#     explorer_addr = blockexplorer.get_address(addr)
#     result = list()
#     for tx in explorer_addr.transactions:
#         outputs = ((item.address, item.value) for item in tx.outputs)
#         outputs = list(filter(lambda item: item[0] == addr, outputs))
#         if len(outputs) > 0:
#             balance = 0
#             for item in outputs:
#                 balance += item[1]
#             balance /= 1e8
#             addr_iter = (item.address for item in tx.inputs + tx.outputs)
#             is_risky = has_malicious_account(addr_iter)
#             result.append({
#                 "txid": tx.hash,
#                 "balance": balance,
#                 "isRisky": is_risky
#             })
#     return result
#
#
# def get_unspent_tx_outputs_of_account(addr: str) -> List[dict]:
#     # noinspection PyTypeChecker
#     outputs = blockexplorer.get_unspent_outputs(addr)
#     return [{
#         "txid": item.tx_hash,
#         "vout": item.tx_output_n
#     } for item in outputs]
#
#
# def get_latest_risky_txs(block_count: int) -> List[dict]:
#     txs = list()
#     block_hash = cli.get_latest_block_hash()
#     for _ in range(block_count):
#         block = cli.get_block(block_hash)
#         block_txs = block['tx']
#         block_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(block['time']))
#         for tx in block_txs:
#             tx['blocktime'] = block_time
#         txs += block_txs
#         block_hash = block['previousblockhash']
#     result = list()
#     for tx in txs:
#         if is_risky_tx(tx):
#             block_time = tx['blocktime']
#             result.append({
#                 "txid": tx['txid'],
#                 "balance": util.get_total_balance(tx),
#                 "time": block_time
#             })
#     return list(sorted(result, key=lambda x: x['balance'], reverse=True))
#
#
# def get_latest_tx_count(block_count: int) -> int:
#     block_hash = cli.get_latest_block_hash()
#     result = 0
#     for _ in range(block_count):
#         block_header = cli.get_block_header(block_hash)
#         result += block_header['nTx']
#         block_hash = block_header['previousblockhash']
#     return result
#
#
# def get_tx_count(start_time: int, end_time: int) -> int:
#     start_time -= 28800
#     end_time -= 28800
#     blocks = mysql.get_block_headers_by_time(start_time, end_time)
#     result = 0
#     for item in blocks:
#         result += item.tx_count
#     return result
#
#
# def get_tx_count_in_recent_hours(hour_count: int) -> List[dict]:
#     result = list()
#     end_time = int(datetime.now().replace(minute=0, second=0, microsecond=0).timestamp())
#     end_time -= 28800
#     start_time = end_time - 3600
#     for _ in range(hour_count):
#         tx_count = get_tx_count(start_time, end_time)
#         time_key = time.strftime("%H:%M", time.localtime(start_time + 28800))
#         result.append({time_key: tx_count})
#         end_time -= 3600
#         start_time -= 3600
#     return list(reversed(result))
#
#
# def get_latest_large_balance_txs(block_count: int, tx_count: int) -> List[dict]:
#     txs = list()
#     block_hash = cli.get_latest_block_hash()
#     for _ in range(block_count):
#         block = cli.get_block(block_hash)
#         block_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(block['time']))
#         block_txs = block['tx']
#         for tx in block_txs:
#             tx['blocktime'] = block_time
#         txs += block_txs
#         block_hash = block['previousblockhash']
#     priority_queue = PriorityQueue()
#     min_balance = 0
#     for tx in txs:
#         total_balance = util.get_total_balance(tx)
#         if total_balance >= min_balance:
#             block_time = tx['blocktime']
#             item = (total_balance, tx['txid'], block_time)
#             priority_queue.put(item)
#             qsize = priority_queue.qsize()
#             if qsize > tx_count:
#                 item = priority_queue.get()
#                 min_balance = item[0]
#     result = list()
#     while not priority_queue.empty():
#         item = priority_queue.get()
#         result.append({
#             "txid": item[1],
#             "balance": item[0],
#             "time": item[2],
#         })
#     return list(reversed(result))
#
#
# def get_latest_large_balance_tx_count(block_count: int, min_balance: float) -> int:
#     block_hash = cli.get_latest_block_hash()
#     result = 0
#     for _ in range(block_count):
#         block = cli.get_block(block_hash)
#         for tx in block['tx']:
#             total_balance = util.get_total_balance(tx)
#             if total_balance >= min_balance:
#                 result += 1
#         block_hash = block['previousblockhash']
#     return result
#
#
# def get_latest_active_addr_count(block_count: int) -> int:
#     block_hash = cli.get_latest_block_hash()
#     result = 0
#     for _ in range(block_count):
#         block = cli.get_block(block_hash)
#         for tx in block['tx']:
#             result += len(tx['vin']) + len(tx['vout'])
#         block_hash = block['previousblockhash']
#     return result
#
#
# def get_active_addr_count(start_time: int, end_time: int) -> int:
#     start_time -= 28800
#     end_time -= 28800
#     blocks = mysql.get_block_headers_by_time(start_time, end_time)
#     result = 0
#     for item in blocks:
#         block = cli.get_block(item.block_hash)
#         for tx in block['tx']:
#             result += len(tx['vin']) + len(tx['vout'])
#     return result
#
#
# def get_active_addr_count_in_recent_hours(hour_count: int) -> List[dict]:
#     result = list()
#     end_time = int(datetime.now().replace(minute=0, second=0, microsecond=0).timestamp())
#     end_time -= 28800
#     start_time = end_time - 3600
#     for _ in range(hour_count):
#         addr_count = get_active_addr_count(start_time, end_time)
#         time_key = time.strftime("%H:%M", time.localtime(start_time + 28800))
#         result.append({time_key: addr_count})
#         end_time -= 3600
#         start_time -= 3600
#     return list(reversed(result))
#
#
# def get_exchange_rates() -> dict:
#     ticker = exchangerates.get_ticker()
#     result = dict()
#     for key in ticker:
#         result[key] = ticker[key].p15min
#     return result
#
#
# def sync_block_headers(batch_size: int):
#     block_num = mysql.count_block_headers()
#     block_hash = cli.get_block_hash(block_num)
#     latest_block_hash = cli.get_latest_block_hash()
#     block_headers = list()
#     while block_hash != latest_block_hash:
#         block = cli.get_block(block_hash, 1)
#         block_num = block['height']
#         block_time = block['time']
#         tx_count = block['nTx']
#         block_headers.append(mysql.BlockHeader(block_num, block_hash, block_time, tx_count))
#         block_hash = block['nextblockhash']
#         if len(block_headers) >= batch_size:
#             mysql.insert_block_headers(block_headers)
#             block_headers.clear()
#         block_num += 1
#     mysql.insert_block_headers(block_headers)
#     pass
#
#
# def run_scheduled_tasks(delay_seconds: int):
#     global cached_risky_transactions
#     global cached_large_balance_transactions
#     global cached_active_address_count_in_recent_hours
#     global cached_transaction_count_in_recent_hours
#     while True:
#         sync_block_headers(batch_size=1000)
#         cached_active_address_count_in_recent_hours = get_active_addr_count_in_recent_hours(hour_count=24)
#         cached_transaction_count_in_recent_hours = get_tx_count_in_recent_hours(hour_count=24)
#         cached_risky_transactions = get_latest_risky_txs(block_count=50)
#         cached_large_balance_transactions = get_latest_large_balance_txs(block_count=50, tx_count=300)
#         time.sleep(delay_seconds)
#     pass
#
#
# mysql.preprocess_bitcoin_abuse_dataset()
# malicious_accounts = mysql.get_all_malicious_accounts()
# cached_risky_transactions = list()
# cached_large_balance_transactions = list()
# cached_active_address_count_in_recent_hours = list()
# cached_transaction_count_in_recent_hours = list()
# Thread(target=run_scheduled_tasks, args=(600,)).start()
